package org.kazao.sms;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;

public class KazaoIncomingMessage extends KazaoMessage {
    public static final int CLASS_ALL = 0;
    public static final int CLASS_REC_UNREAD = 1;
    public static final int CLASS_REC_READ = 2;
    public static final int CLASS_STO_UNSENT = 3;
    public static final int CLASS_STO_SENT = 4;
    
    private String[] long_code = new String[0];
    
    public KazaoIncomingMessage(Date date, String originator, String text, int memIndex) {
        super(TYPE_INCOMING, date, originator, null, text, memIndex, false, false);
        initLong();
    }
    
    protected KazaoIncomingMessage(String pdu, int memIndex) {
        super(TYPE_INCOMING, null, null, null, null, memIndex, false, false);
        initLong();
        Date date;
        String originator, text;
        String str1, str2;
        int index, i, j, k, protocol, addr, year, month, day, hour, min, sec;
        
        str1 = pdu.substring(0, 2);
        i = Integer.parseInt(str1, 16);
        index = (i + 1) * 2;
        index += 2;
        
        str1 = pdu.substring(index, index + 2);
        i = Integer.parseInt(str1, 16);
        j = index + 4;
        originator = "";
        for (k = 0; k < i; k += 2) {
            originator = originator + pdu.charAt(j + k + 1) + pdu.charAt(j + k);
        }
        originator = "+" + originator;
        if (originator.charAt(originator.length() - 1) == 'F') {
            originator = originator.substring(0, originator.length() - 1);
        }
        // Type of Address
        addr = Integer.parseInt(pdu.substring(j - 2, j), 16);
        if ( (addr & (1 << 6)) != 0 && (addr & (1 << 5)) == 0 && (addr & (1 << 4)) != 0) {
            //Alphanumeric, (coded according to GSM TS 03.38 7-bit default alphabet)
            str1 = pduToText(pdu.substring(j, j + k));
            originator = "";
            for (i = 0; i < str1.length(); i++) {
                if ( (int) str1.charAt(i) == 27) {
                    originator += KazaoGSMAlphabets.hex2ExtChar( (int) str1.charAt(++i), KazaoGSMAlphabets.GSM7BITDEFAULT);
                } else {
                    originator += KazaoGSMAlphabets.hex2Char( (int) str1.charAt(i), KazaoGSMAlphabets.GSM7BITDEFAULT);
                }
            }
        }
        //else if ( (addr & (1 << 6)) == 0 && (addr & (1 << 5)) == 0 && (addr & (1 << 4)) != 0) originator = "+" + originator;
        
        index = j + k + 2;
        str1 = "" + pdu.charAt(index) + pdu.charAt(index + 1);
        protocol = Integer.parseInt(str1, 16);
        index += 2;
        year = Integer.parseInt("" + pdu.charAt(index + 1) + pdu.charAt(index)); index += 2;
        month = Integer.parseInt("" + pdu.charAt(index + 1) + pdu.charAt(index)); index += 2;
        day = Integer.parseInt("" + pdu.charAt(index + 1) + pdu.charAt(index)); index += 2;
        hour = Integer.parseInt("" + pdu.charAt(index + 1) + pdu.charAt(index)); index += 2;
        min = Integer.parseInt("" + pdu.charAt(index + 1) + pdu.charAt(index)); index += 2;
        sec = Integer.parseInt("" + pdu.charAt(index + 1) + pdu.charAt(index)); index += 4;
        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.YEAR, year + 2000);
        cal.set(Calendar.MONTH, month - 1);
        cal.set(Calendar.DAY_OF_MONTH, day);
        cal.set(Calendar.HOUR_OF_DAY, hour);
        cal.set(Calendar.MINUTE, min);
        cal.set(Calendar.SECOND, sec);
        date = cal.getTime();
        switch (protocol & 0x0C) {
            case 0:
                String long_sms = "";
                if (isLongSms(pdu.substring(index + 2))) {
                    long_sms = "["+pdu.substring(index + 2 + 6, index + 2 + 8)+":" +
                            hex2int(pdu.substring(index + 2 + 10, index + 2 + 12)) +"/"+
                            hex2int(pdu.substring(index + 2 + 8, index + 2 + 10)) +"]";
                    str1 =  pduToText(pdu.substring(index + 2)).substring(7);
                } else {
                    str1 = pduToText(pdu.substring(index + 2));
                }
                str2 = "";
                for (i = 0; i < str1.length(); i ++) {
                    if ((int) str1.charAt(i) == 27) {
                        str2 += KazaoGSMAlphabets.hex2ExtChar((int) str1.charAt(++i), KazaoGSMAlphabets.GSM7BITDEFAULT);
                    } else {
                        str2 += KazaoGSMAlphabets.hex2Char((int) str1.charAt(i), KazaoGSMAlphabets.GSM7BITDEFAULT);
                    }
                }
                str1 = long_sms+str2;
                break;
            case 4:
                index += 2;
                str1 = "";
                while (index < pdu.length()) {
                    i = Integer.parseInt("" + pdu.charAt(index) + pdu.charAt(index + 1), 16);
                    str1 = str1 + (char) i;
                    index += 2;
                }
                break;
            case 8:
                index += 2;
                str1 = "";
                while (index < pdu.length()) {
                    i = Integer.parseInt("" + pdu.charAt(index) + pdu.charAt(index + 1), 16);
                    j = Integer.parseInt("" + pdu.charAt(index + 2) + pdu.charAt(index + 3), 16);
                    str1 = str1 + (char) ((i * 256) + j);
                    index += 4;
                }
                break;
        }
        
        setOriginator(originator);
        setDate(date);
        setText(str1);
    }
    
    public void setOriginator(String originator) {
        this.originator = originator; }
    
    public String getOriginator() {
        return originator; }
    
    private String pduToText(String pdu) {
        String text;
        byte oldBytes[], newBytes[];
        BitSet bitSet;
        int i, j, value1, value2;
        
        oldBytes = new byte[pdu.length() / 2];
        for (i = 0; i < pdu.length() / 2; i ++) {
            oldBytes[i] = (byte) (Integer.parseInt(pdu.substring(i * 2, (i * 2) + 1), 16) * 16);
            oldBytes[i] += (byte) Integer.parseInt(pdu.substring((i * 2) + 1, (i * 2) + 2), 16);
        }
        
        bitSet = new BitSet(pdu.length() / 2 * 8);
        value1 = 0;
        for (i = 0; i < pdu.length() / 2; i ++)
            for (j = 0; j < 8; j ++) {
            value1 = (i * 8) + j;
            if ((oldBytes[i] & (1 << j)) != 0) bitSet.set(value1);
            }
        value1 ++;
        
        value2 = value1 / 7;
        if (value2 == 0) value2 ++;
        
        newBytes = new byte[value2];
        for (i = 0; i < value2; i ++) {
            for (j = 0; j < 7; j ++) {
                if ((value1 + 1) > (i * 7 + j)) {
                    if (bitSet.get(i * 7 + j)) {
                        newBytes[i] |= (byte) (1 << j);
                    }
                }
            }
        }
        if (newBytes[value2 - 1] == 0) {
            text = new String(newBytes, 0, value2 - 1);
        } else {
            text = new String(newBytes);
        }
        return text;
    }
    
    private int hex2int(String hex) {
        int result = 0;
        for (int i=0; i < hex.length(); i++) {
            result += hex2int(hex.charAt(i))*Math.pow(16, hex.length()-i-1);
        }
        return result;
    }
    
    private int hex2int(char hex) {
        int result = -1;
        if (hex == '0') {
            result =  0;
        } else if (hex == '1') {
            result =  1;
        } else if (hex == '2') {
            result =  2;
        } else if (hex == '3') {
            result =  3;
        } else if (hex == '4') {
            result =  4;
        } else if (hex == '5') {
            result =  5;
        } else if (hex == '6') {
            result =  6;
        } else if (hex == '7') {
            result =  7;
        } else if (hex == '8') {
            result =  8;
        } else if (hex == '9') {
            result =  9;
        } else if (hex == 'A') {
            result =  10;
        } else if (hex == 'B') {
            result =  11;
        } else if (hex == 'C') {
            result =  12;
        } else if (hex == 'D') {
            result =  13;
        } else if (hex == 'E') {
            result =  14;
        } else if (hex == 'F') {
            result =  15;
        }
        return result;
    }
    
    private void initLong() {
        File f = new File(System.getProperty("user.dir")+"/kazao.phone");
        if (f.exists()) {
            String res = "";
            try {
                FileInputStream fis = new FileInputStream(f.toString());        
                int x = 0;
                while (x != -1) {
                    x = fis.read();
                    if (x != -1) {
                        res += (char) x;
                    }
                }
                fis.close();
                long_code = res.split(":");
            } catch (FileNotFoundException ex) {
                ex.printStackTrace();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        } else {
            InputStream is = getClass().getResourceAsStream("/org/kazao/sms/kazao.phone");
            String res = "";
            int x = 0;
            try {
                while (x != -1) {
                    x = is.read();
                    if (x != -1) {
                        res += (char) x;
                    }
                }
                is.close();
                long_code = res.split(":");
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
    }
    
    private boolean isLongSms(String code) {
        boolean result = false;
        for (int i=0; i < long_code.length; i++) {
            if (code.startsWith(long_code[i])) {
                result = true;
                break;
            }
        }
        return result;
    }
}
